package com.quick.develop.flowable.framework.cmd;

import cn.hutool.core.map.MapUtil;
import com.quick.develop.flowable.constant.BpmConstants;
import com.quick.develop.flowable.enums.BpmExecuteCmd;
import com.quick.develop.framework.utils.uuid.IdUtils;
import com.quick.develop.framework.security.utils.SecurityUtils;
import com.quick.develop.flowable.utils.BpmTaskUtil;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.HistoryService;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.flowable.engine.impl.cmd.NeedsActiveTaskCmd;
import org.flowable.engine.impl.persistence.entity.*;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.task.service.HistoricTaskService;
import org.flowable.task.service.impl.persistence.entity.HistoricTaskInstanceEntity;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.flowable.variable.api.history.HistoricVariableInstance;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * @author junyuan.liu
 * @description: 为 转办、委派 产生历史记录，直接伪造数据插入
 *                      1、ACT_HI_TASKINST 已办数据
 *                      2、ACT_HI_ACTINST  流程图点数据
 * @date 2022/8/18 18:51
 */
public class CreateHistoricDataCmd extends NeedsActiveTaskCmd<Void> {
    private static final long serialVersionUID = -8494315345062674030L;
    

    protected String toAssignee;
    protected String message;
    protected BpmExecuteCmd cmd;

    public CreateHistoricDataCmd(String taskId, String toAssignee, String message, BpmExecuteCmd cmd) {
        super(taskId);
        this.toAssignee = toAssignee;
        this.message = message;
        this.cmd = cmd;
    }

    @Override
    protected Void execute(CommandContext commandContext, TaskEntity taskEntity) {
        CommentEntityManager commentEntityManager = CommandContextUtil.getCommentEntityManager(commandContext);
        HistoricTaskService historicTaskService = CommandContextUtil.getHistoricTaskService(commandContext);
        HistoricActivityInstanceEntityManager historicActivityInstanceEntityManager = CommandContextUtil.getHistoricActivityInstanceEntityManager(commandContext);

        CommentEntity comment = createComment(commandContext, null, taskEntity);
        HistoricTaskInstanceEntity hisSubTask = buildHisSubTask(commandContext, historicTaskService, taskEntity, comment);
        HistoricActivityInstanceEntity hisActivity = buildHisActivity(commandContext, hisSubTask);

        comment.setTaskId(hisSubTask.getId());
        commentEntityManager.insert(comment, false);
        historicTaskService.insertHistoricTask(hisSubTask, false);
        historicActivityInstanceEntityManager.insert(hisActivity, false);

        return null;
    }

    protected HistoricTaskInstanceEntity buildHisSubTask(CommandContext commandContext, HistoricTaskService historicTaskService, TaskEntity task, CommentEntity comment) {
        HistoricTaskInstanceEntity historicTask = historicTaskService.createHistoricTask(task);

        ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);
        HistoryService historyService = processEngineConfiguration.getHistoryService();
        ProcessDefinitionEntityManager processDefinitionEntityManager = CommandContextUtil.getProcessDefinitionEntityManager(commandContext);
        HistoricProcessInstanceEntityManager historicProcessInstanceEntityManager = CommandContextUtil.getHistoricProcessInstanceEntityManager(commandContext);
        ProcessDefinitionEntity processDefinition = processDefinitionEntityManager.findById(historicTask.getProcessDefinitionId());
        HistoricProcessInstanceEntity historicProcessInstance = historicProcessInstanceEntityManager.findById(historicTask.getProcessInstanceId());
        List<HistoricVariableInstance> varList = historyService.createHistoricVariableInstanceQuery().processInstanceId(historicTask.getProcessInstanceId()).list();
        Map<String, Object> variables = varList.stream()
                .collect(HashMap::new,(map, item)->map.put(item.getVariableName(),item.getValue()), HashMap::putAll
                );

//        String formCode =  MapUtil.getStr(variables, BpmConstants.BUSINESS_CODE);
        String startUserName = MapUtil.getStr(variables, BpmConstants.INITIATOR_NAME);

        historicTask.setId(IdUtils.randomUUID());
        historicTask.setTaskDefinitionId(processDefinition.getKey());
        historicTask.setScopeId(historicProcessInstance.getBusinessKey());
        historicTask.setSubScopeId(processDefinition.getCategory());
        historicTask.setScopeDefinitionId(processDefinition.getName());
//        Optional.ofNullable(formCode).ifPresent(historicTask::setFormKey);
        historicTask.setScopeType(cmd.getCmd());
        historicTask.setParentTaskId(task.getId());
        historicTask.setEndTime(CommandContextUtil.getProcessEngineConfiguration(commandContext).getClock().getCurrentTime());
        historicTask.setDurationInMillis(historicTask.getEndTime().getTime() - historicTask.getCreateTime().getTime());
        buildDesc(historicTask, startUserName, comment.getFullMessage());

        return historicTask;
    }

    private void buildDesc( HistoricTaskInstanceEntity historicTask, String startUserName , String comment) {
        String description = historicTask.getDescription();
        /*拼接流程名称*/
//        String txt = BpmTaskUtil.concatDescription(description, BpmConstants.PROCESS_NAME_SP + processName);
        /*拼接流程发起者*/
        String txt = BpmTaskUtil.concatDescription(description, BpmConstants.START_USER_SP + startUserName);
        /*拼接任务审批结果*/
        txt = BpmTaskUtil.concatDescription(txt, BpmConstants.COMMENT_SP + comment);

        historicTask.setDescription(txt);

    }
    
    protected HistoricActivityInstanceEntity buildHisActivity(CommandContext commandContext, HistoricTaskInstanceEntity historicTask) {
        HistoricActivityInstanceEntityManager historicActivityInstanceEntityManager = CommandContextUtil.getHistoricActivityInstanceEntityManager(commandContext);
        ActivityInstanceEntity activityInstance = CommandContextUtil.getActivityInstanceEntityManager(commandContext).findActivityInstanceByTaskId(taskId);
        
        HistoricActivityInstanceEntity entity = historicActivityInstanceEntityManager.create(activityInstance);
        entity.setId(IdUtils.randomUUID());
        entity.setTaskId(historicTask.getId());
        entity.setStartTime(historicTask.getCreateTime());
        entity.setEndTime(CommandContextUtil.getProcessEngineConfiguration(commandContext).getClock().getCurrentTime());
        entity.setDurationInMillis(entity.getEndTime().getTime() - entity.getStartTime().getTime());
        

        return entity;
    }
    
    protected CommentEntity createComment(CommandContext commandContext, String id, TaskEntity task){
        String userCode = SecurityUtils.getUserCode();
        String user = SecurityUtils.getUsername(); // "【" + userCode + "】" + 
        CommentEntityManager commentEntityManager = CommandContextUtil.getCommentEntityManager(commandContext);
        CommentEntity comment = (CommentEntity) commentEntityManager.create();
        comment.setTaskId(id);
        comment.setProcessInstanceId(task.getProcessInstanceId());
        comment.setUserId(userCode);
        comment.setType(cmd.getCmd());
        comment.setTime(CommandContextUtil.getProcessEngineConfiguration(commandContext).getClock().getCurrentTime());
        comment.setAction(BpmConstants.ADD_COMMENT);
        StringBuilder eventMessage = new StringBuilder();
        eventMessage.append(cmd.msg).append("：").append(user)
                .append(" → ").append(toAssignee);
        Optional.ofNullable(message)
                .ifPresent(c -> {
                    if (eventMessage.length() == 0){
                        eventMessage.append(c);
                    }else {
                        eventMessage.append("；").append(c);
                    }
                });
        
        String fullStr = eventMessage.toString().replaceAll("\\s+", " ");
        
        comment.setMessage(fullStr.length() > 163 ? fullStr.substring(0, 160) + "..." : fullStr);
        comment.setFullMessage(fullStr);
        return comment;

    }
}
